#ifndef _MEETING_MANAGE_CPP
#define _MEETING_MANAGE_CPP

#include "MeetingManage.h"
#include "UserManage.h"
#include "Date.h"
#include <algorithm>
#include <list>
using namespace std;


// ===== Static object initialization ===== 
bool MeetingManage::instanceFlag_ = false;
MeetingManage* MeetingManage::instance_ = NULL;



MeetingManage::MeetingManage() {
	meetings_.clear();
}


MeetingManage* MeetingManage::getInstance() {

	// check if the instance_ has been initialized ..
	if(instanceFlag_==false) {
		instance_ = new MeetingManage();
		instanceFlag_ = true;
	}

	// return the instance_ ..
	return instance_;
}


MeetingManage::~MeetingManage() {
	delete instance_;
	instanceFlag_ = false;
}


bool MeetingManage::addMeeting( string sponsor, string participator, Date stime, Date etime, string title ) {
	// Add a meeting to the meeting management

	// check if the time valid ..
	if(!(Date::isValid(stime) && Date::isValid(etime))) return false; // not valid, return false 
	if(stime>=etime) return false; // not valid, return false

	// check if the username valid ..
	if(UserManage::getInstance()->findUserByName(sponsor)==NULL || UserManage::getInstance()->findUserByName(participator)==NULL) return false; // no such user, return false

	// check if the title conflict or time conflict ..
	for(list<Meeting>::iterator it=meetings_.begin();it!=meetings_.end();++it) {
		// title conflict, return false ..
		if(it->getTitle() == title) return false; 

		// check if sponsor has time conflict ..
		if(it->getSponsor()==sponsor || it->getParticipator()==sponsor) {
			if(!(it->getStartDate()>etime || it->getEndDate()<stime)) return false; // sponsor time conflict, return false 
		}

		// check if participator time conflict ..
		if(it->getSponsor()==participator || it->getParticipator()==participator) {
			if(!(it->getStartDate()>etime || it->getEndDate()<stime)) return false; // participator time conflict, return false 
		}
	}

	// initialize a meeting ..
	Meeting mt(sponsor, participator, stime, etime, title);

	// add to the meeting management ..
	meetings_.push_back(mt);

	// successful, return true ..
	return true;
}


bool MeetingManage::deleteMeeting( string userName, string title ) {
	// Delete a meeting by title

	list<Meeting>::iterator it;


	// check if the meeting exists ..
	for(it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getTitle()==title) {
			// meeting exist, check if the user is the sponsor ..
			if(it->getSponsor()==userName) {
				// delete the meeting ..
				meetings_.erase(it);

				// successful, return true ..
				return true;
			}
		}
	}

	// fail, return false ..
	return false;
}


bool MeetingManage::deleteAllMeetings( string userName ) {
	// Delete all the meetings_ of a user

	// loop find the meetings_ as a sponsor ..
	for(list<Meeting>::iterator it=meetings_.begin() ;it!=meetings_.end(); ) {
		if(it->getSponsor()==userName) {
			it = meetings_.erase(it);
		}
		else {
			++it;
		}
	}

	// check if any meeting remains ..
	return (this->listAllMeetings(userName).size() == 0);
}


bool MeetingManage::updateMeetingParticipator( string title, string newParticipator ) {
	// Update the participator of a meeting 

	list<Meeting>::iterator it;


	// find the meeting ..
	for(it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getTitle()==title) {
			// found, reset the participator ..
			it->setParticipator(newParticipator);
			return true;
		}
	}

	// not found, return false ..
	return false;
}


bool MeetingManage::updateMeetingStartDate( string title, Date newStartDate ) {
	// Update the start date of a meeting 

	list<Meeting>::iterator it;


	// find the meeting ..
	for(it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getTitle()==title) {
			// found, reset the start date ..
			it->setStartDate(newStartDate);
			return true;
		}
	}

	// not found, return false ..
	return false;
}


bool MeetingManage::updateMeetingEndDate( string title, Date newEndDate ) {
	// Update the end date of a meeting 

	list<Meeting>::iterator it;


	// find the meeting ..
	for(it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getTitle()==title) {
			// found, reset the end date ..
			it->setEndDate(newEndDate);
			return true;
		}
	}

	// not found, return false ..
	return false;
}


Meeting* MeetingManage::queryMeetingByTitle( string title ) {
	// Return a pointer to a meeting by its title 

	list<Meeting>::iterator it;


	// find the meeting by its title ..
	for(it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getTitle()==title) {
			// found, return the meeting pointer ..
			return &(*it);
		}
	}

	// not found, return NULL ..
	return NULL;
}


list<Meeting> MeetingManage::queryMeetingsByTime( string userName, Date stime, Date etime ) {
	// Return meetings during the time period entirely

	list<Meeting> mts; mts.clear();


	// find the meetings ..
	for(list<Meeting>::iterator it=meetings_.begin();it!=meetings_.end();++it) {
		if((it->getStartDate()>=stime && it->getEndDate()<=etime) && (it->getSponsor()==userName || it->getParticipator()==userName)) {
			mts.push_back(*it);
		}
	}

	// return the result ..
	return mts;
}


list<Meeting> MeetingManage::listAllMeetings( string userName ) {
	// List all meetings_ of a user 

	list<Meeting> mts; mts.clear();


	// find the meetings_ ..
	for(list<Meeting>::iterator it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getSponsor()==userName || it->getParticipator()==userName) {
			mts.push_back(*it);
		}
	}

	// return the result ..
	return mts;
}


list<Meeting> MeetingManage::listAllSponsorMeetings( string userName ) {
	// List all sponsor meetings_ of a user 

	list<Meeting> mts; mts.clear();


	// find the meetings_ ..
	for(list<Meeting>::iterator it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getSponsor()==userName) {
			mts.push_back(*it);
		}
	}

	// return the result ..
	return mts;
}


list<Meeting> MeetingManage::listAllParticipateMeetings( string userName ) {
	// List all participator meetings_ of a user 

	list<Meeting> mts; mts.clear();


	// find the meetings_ ..
	for(list<Meeting>::iterator it=meetings_.begin();it!=meetings_.end();++it) {
		if(it->getParticipator()==userName) {
			mts.push_back(*it);
		}
	}

	// return the result ..
	return mts;
}


list<Meeting> MeetingManage::acquireMeetingsList() {
	// Return all the data of meetings_

	// return the result ..
	return this->meetings_;
}


void MeetingManage::initMeetingsList( std::list<Meeting> meetings )
{
	this->meetings_ = meetings;
}


#endif
